package cuishifeng.blog.markdown;

import java.util.Arrays;

import com.vladsch.flexmark.ast.Node;
import com.vladsch.flexmark.convert.html.FlexmarkHtmlParser;
import com.vladsch.flexmark.ext.anchorlink.AnchorLinkExtension;
import com.vladsch.flexmark.ext.autolink.AutolinkExtension;
import com.vladsch.flexmark.ext.definition.DefinitionExtension;
import com.vladsch.flexmark.ext.emoji.EmojiExtension;
import com.vladsch.flexmark.ext.footnotes.FootnoteExtension;
import com.vladsch.flexmark.ext.gfm.issues.GfmIssuesExtension;
import com.vladsch.flexmark.ext.gfm.strikethrough.StrikethroughExtension;
import com.vladsch.flexmark.ext.gfm.tasklist.TaskListExtension;
import com.vladsch.flexmark.ext.gfm.users.GfmUsersExtension;
import com.vladsch.flexmark.ext.ins.InsExtension;
import com.vladsch.flexmark.ext.jekyll.tag.JekyllTagExtension;
import com.vladsch.flexmark.ext.tables.TablesExtension;
import com.vladsch.flexmark.ext.toc.SimTocExtension;
import com.vladsch.flexmark.ext.toc.TocExtension;
import com.vladsch.flexmark.ext.typographic.TypographicExtension;
import com.vladsch.flexmark.ext.wikilink.WikiLinkExtension;
import com.vladsch.flexmark.html.HtmlRenderer;
import com.vladsch.flexmark.parser.Parser;
import com.vladsch.flexmark.superscript.SuperscriptExtension;
import com.vladsch.flexmark.util.options.MutableDataSet;

/**
 * @author cuishifeng
 * Created on 2021-01-31
 */
public class MarkdownParser {

    private static MarkdownParser markdownParser = new MarkdownParser();

    public static MarkdownParser getInstance() {
        return markdownParser;
    }

    private static final MutableDataSet OPTIONS = new MutableDataSet()
            .set(HtmlRenderer.INDENT_SIZE, 2)
            .set(HtmlRenderer.PERCENT_ENCODE_URLS, true)
//            .set(HtmlRenderer.CODE)
            .set(Parser.LISTS_AUTO_LOOSE, false)
            .set(Parser.BLANK_LINES_IN_AST, true)
            .set(FlexmarkHtmlParser.OUTPUT_ATTRIBUTES_ID, true)

            /** emoji 设置 */
//            .set(EmojiExtension.ROOT_IMAGE_PATH, "https://raw.githubusercontent.com/WebpageFX/emoji-cheat-sheet.com/master/public/graphics/emojis/")
            /** 锚链接 id属性的标头呈现锚链接*/
            .set(HtmlRenderer.GENERATE_HEADER_ID, true)
            /** toc 目录标题标签 带有id */
            .set(HtmlRenderer.RENDER_HEADER_ID, false)
//            .set(TocExtension.IS_NUMBERED,false)  // 使用有序列表来生成标题列表
            /** 使用GitHub ID生成算法自动将锚链接添加到标题 */
            .set(AnchorLinkExtension.ANCHORLINKS_ANCHOR_CLASS, "anchor")
//            .set(AnchorLinkExtension.ANCHORLINKS_TEXT_PREFIX, "<svg aria-hidden=\"true\" class=\"octicon octicon-link\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg>")
            .set(AnchorLinkExtension.ANCHORLINKS_WRAP_TEXT, false)
//            .set(AnchorLinkExtension.ANCHORLINKS_NO_BLOCK_QUOTE, true)
//            .set(AnchorLinkExtension.ANCHORLINKS_ANCHOR_CLASS,"bb")
            /** 定义列表 将Php Markdown Extra Definition List的定义语法转换为 */
            .set(DefinitionExtension.COLON_MARKER, true)
            /** 脚注 footnotes */
            .set(FootnoteExtension.FOOTNOTE_BACK_LINK_REF_CLASS, "footnote-ref")
            .set(FootnoteExtension.FOOTNOTE_REF_PREFIX, "[")
            .set(FootnoteExtension.FOOTNOTE_REF_SUFFIX, "]")
            .set(FootnoteExtension.FOOTNOTE_BACK_REF_STRING, "&lt;back&gt;")
            /** Gfm-Users */
            .set(GfmUsersExtension.GIT_HUB_USERS_URL_ROOT, "http://www.kazhikazhi.com")
            /** 表格 */
            .set(TablesExtension.COLUMN_SPANS, false)
            .set(TablesExtension.APPEND_MISSING_COLUMNS, true)
            .set(TablesExtension.DISCARD_EXTRA_COLUMNS, true)
            .set(TablesExtension.HEADER_SEPARATOR_COLUMN_MATCH, true)

            .set(Parser.EXTENSIONS, Arrays.asList(
                    // 博客图片转换
                    ImageUrlExtension.create(),
                    EmojiExtension.create(),
                    // emoji
                    TablesExtension.create(),
                    // 表格 || 跨越两列 通过|在单元末尾添加连续字来指定列跨度
                    TocExtension.create(),
                    SimTocExtension.create(),
                    WikiLinkExtension.create(),
//                    StrikethroughSubscriptExtension.create(),
                    // 使用GitHub ID生成算法自动将锚链接添加到标题
                    AnchorLinkExtension.create(),
                    // 自动链接
                    AutolinkExtension.create(),
                    // 定义列表
                    DefinitionExtension.create(),
                    // 脚注
                    FootnoteExtension.create(),
                    // Gfm-Issues
                    GfmIssuesExtension.create(),
                    // Gfm-Strikethrough/Subscript ~~ 删除线
                    StrikethroughExtension.create(),
                    // Gfm-TaskList [ ]，[x]或。启用基于列表项目的任务列表[X]
                    TaskListExtension.create(),
                    // Gfm-Users ***
                    GfmUsersExtension.create(),
                    // 将文字放在文本中来启用文本标记++。例如，在hey ++you++
                    InsExtension.create(),
                    // Jekyll标签 ***
                    JekyllTagExtension.create(),
                    //通过将文字放在文本中来启用文本标记^ hey ^you^
                    SuperscriptExtension.create(),
//                    JiraConverterExtension.create(), // jada文本格式转化
                    // 印刷字符处理
                    TypographicExtension.create()
            )); //

    static final Parser PARSER = Parser.builder(OPTIONS).build();
    static final HtmlRenderer RENDERER = HtmlRenderer.builder(OPTIONS).build();


    /**
     * 获取文章md转换成html
     *
     * @param md
     * @return
     */
    public static String getHTML(String md) {
        Node document = PARSER.parse(md);
        String html = RENDERER.render(document);
        return html;
    }


    /**
     * 获取文章目录html by 转换好的html
     *
     * @param html
     * @return
     */
    public static String getTOC(String html) {
        int num = html.indexOf("<p><span class=\"end\">");
        String toc = html.substring(0, num);
        return toc;
    }

    /**
     * 修改或添加MD目录 - 保存文章时执行
     *
     * @param md
     * @return
     */
    public static String saveMD(String md) {
        StringBuilder endMD = new StringBuilder();
        String rp = "[TOC]  \n" +
                "<span class=\"end\"></span>\n";
        if (md.startsWith("[TOC]")) {
            md.replaceAll("[TOC]", rp);
            endMD.append(md);
        } else {
            endMD.append(rp).append(md);
        }
        return endMD.toString();
    }
}
